import axios, {AxiosInstance, AxiosError, AxiosRequestConfig, AxiosResponse} from 'axios'
import {ElMessage} from 'element-plus'
import {Session} from "@/utils/storage";
import {UserService} from "@/api/user/login";

const URL: string = import.meta.env.MODE as string === 'development' ? '/api' : '/api'

enum Status {
    //操作成功
    SUCCESS = 100,
    //缺少token
    NO_TOKEN = 101,
    //token失效
    TOKEN_LOSE_EFFICACY,
    //权限不足
    FORBIDDEN,
    //业务异常
    BUSINESS_EXCEPTION
}

const config = {
    headers: {
        "Content-Type": "application/json;charset=UTF-8",
        // "Access-Control-Allow-Origin-Type": '*'
    },
    // 默认地址
    baseURL: URL,
    // 设置超时时间
    timeout: 20000,
    // 表示跨域请求时是否需要使用凭证
    withCredentials: false,
}

class RequestHttp {
    // 定义成员变量并指定类型
    service: AxiosInstance;

    public constructor(config: AxiosRequestConfig) {
        // 实例化axios
        this.service = axios.create(config);

        /**
         * 请求拦截器
         * 客户端发送请求 -> [请求拦截器] -> 服务器
         * token校验(JWT) : 接受服务器返回的token,存储到vuex/pinia/本地储存当中
         */
        this.service.interceptors.request.use(
            (config: AxiosRequestConfig | any) => {
                const token = Session.get('token') || '';
                //若请求方式为post，则将data参数转为JSON字符串
                // if (config.method === 'POST') {
                //     config.data = JSON.stringify(config.data);
                // }
                return {
                    ...config,
                    headers: {
                        'token': token, // 请求头中携带token信息
                    }
                }
            },
            (error: AxiosError) => {
                // 请求报错
                Promise.reject(error).then(r => r)
            }
        )

        /**
         * 响应拦截器
         * 服务器换返回信息 -> [拦截统一处理] -> 客户端JS获取到信息
         */
        this.service.interceptors.response.use(
            (response: AxiosResponse | any) => {
                if (response.headers.token) {
                    let token: string = response.headers.token as string;
                    console.log('获取到后端的token', token)
                    Session.set('token', token)
                }
                const {data, config, request} = response; // 解构
                // 全局错误信息拦截（防止下载文件得时候返回数据流，没有code，直接报错）
                if (data.code && data.code !== Status.SUCCESS) {
                    if (data.code == Status.NO_TOKEN) {
                        ElMessage.error('缺少token，请重新登陆')
                        setTimeout(() => {
                            UserService.loginOut()
                        }, 1000)
                        return
                    } else if (data.code == Status.TOKEN_LOSE_EFFICACY) {
                        ElMessage.error('token失效，请重新登陆')
                        setTimeout(() => {
                            UserService.loginOut()
                        }, 1000)
                        return
                    } else {
                        ElMessage.error(data.message)
                    }
                    return Promise.reject(data)
                }
                // if (request.responseType === 'blob') {
                //     return response
                // }
                return response;
            },
            (error: AxiosError) => {

                const {response} = error;
                if (response) {
                    let message = this.showMessage(response.status);
                    ElMessage.error(message)
                    return Promise.reject(response.data)
                }
                if (!window.navigator.onLine) {
                    ElMessage.error('网络连接失败');
                    // 可以跳转到错误页面，也可以不做操作
                    // return router.replace({
                    //   path: '/404'
                    // });
                }
            }
        )
    }

    showMessage(code: number): string {
        let message: string;
        switch (code) {
            case 400:
                message = "请求错误(400)";
                break;
            case 401:
                message = "未授权，请重新登录(401)";
                break;
            case 403:
                message = "拒绝访问(403)";
                break;
            case 404:
                message = "请求出错(404)";
                break;
            case 408:
                message = "请求超时(408)";
                break;
            case 500:
                message = "服务器错误(500)";
                break;
            case 501:
                message = "服务未实现(501)";
                break;
            case 502:
                message = "网络错误(502)";
                break;
            case 503:
                message = "服务不可用(503)";
                break;
            case 504:
                message = "网络超时(504)";
                break;
            case 505:
                message = "HTTP版本不受支持(505)";
                break;
            default:
                message = `连接出错(${code})`;
                break;
        }
        return `${message}`;
    }

    // 拥有如下便捷方法
    public get<T = any>(
        url: string,
        config?: AxiosRequestConfig
    ): Promise<AxiosResponse<IResultData<T>>> {
        return this.service.get(url, config);
    }

    public post<T = any>(
        url: string,
        data?: any,
        config?: AxiosRequestConfig
    ): Promise<AxiosResponse<IResultData<T>>> {
        return this.service.post(url, data, config);
    }

    public put<T = any>(
        url: string,
        data?: any,
        config?: AxiosRequestConfig
    ): Promise<AxiosResponse<IResultData<T>>> {
        return this.service.put(url, data, config);
    }

    public delete<T = any>(
        url: string,
        config?: AxiosRequestConfig
    ): Promise<AxiosResponse<IResultData<T>>> {
        return this.service.delete(url, config);
    }
}

let requestHttp = new RequestHttp(config);
// 导出一个实例对象
export default requestHttp;
